home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / cxref.arc / CXREF.C next >
Encoding:
C/C++ Source or Header  |  1987-01-26  |  22.6 KB  |  937 lines

  1. /*
  2.     CPRINT, Print a (fairly) neat listing of a c program
  3.  
  4.     Programmed by Andrew L. Bender, M. D.
  5.     
  6.     June 24, 1984 - Version 1.0
  7.     June 26, 1984 - Version 1.1
  8.         Fix some bugs in string processing
  9.     July 3, 1984 - Version 1.2
  10.         Allow for printer file device.
  11.         Count source statements
  12.         
  13.     The following modifications were made by Bud Curtis
  14.     
  15.     Nov 2, 1986 - version 1.3
  16.         Modified CPRINT for Datalight C compiler
  17.         
  18.     Jan 15, 1987 - version 1.4
  19.         Added X-reference and listing highlight features
  20.  
  21.     Permission is hereby given to freely distribute this
  22.     program but it may not be sold.  This program may be
  23.     modified by anyone as long as this notice remains.
  24.     
  25.     The listing contains three columns on the left:
  26.     
  27.     column 1 is an indicator that a qoute or comment is continuing 
  28.          to the next print line (* -> comment, " -> quote)
  29.     
  30.     column 2 is the "nesting level" of compound statements
  31.     
  32.     column 3 is a rough idea of what the line number will be.
  33.          It is actually a count of "\n" characters. 
  34.          
  35.     The heading on each page gives the name of the file being
  36.     printed and the date the listing was created.
  37.  
  38.     If braces, brackets or parenthesis are unbalanced
  39.     this will be reported at the end of the listing.
  40.     A complete syntactical analysis of the program
  41.     would require more effort but would be worth it as
  42.     an exercise of much value in learning the c language
  43.     because of the facility and fluency needed to write
  44.     such a checker.
  45.     
  46.     A program checker "lint" is quite thorough in its
  47.     analysis of c programs and is available on most
  48.     UNIX systems.
  49. */
  50. #include <stdio.h>
  51. #include <time.h>
  52. #include <ctype.h>
  53. #include <memory.h>
  54. #include <proto.h>
  55. #define    LPP        58            /* Lines per page printed */
  56. #define    TAB        3            /* Number of spaces per TAB charactes */
  57. #define    CHPL    68            /* Characters per line printed */
  58. #define FALSE   0
  59. #define TRUE    1 == 1
  60. #define LMAX     500            /* maximum line number entries in table */
  61. #define DKW     12            /* total number of data definition key words */
  62. #define KW         21            /* total number of reserved key words */
  63. #define NREF     9            /* number of reference entries per refno structure */
  64. #define NFCN    3 * 57        /* number of separate functions possible */
  65.  
  66. int pagect, level, tabct, lines, stmnt, linect, fline;
  67.  
  68. time_t timer;
  69. struct tm time_stamp;
  70.  
  71. typedef int boolean;
  72. boolean overflow = FALSE;
  73. boolean pre_def = TRUE;                /* flag to indicate past first function */
  74. boolean p_func = FALSE;                /* potential function name flag */
  75. boolean listing = TRUE;                /* generate source listing */
  76. boolean gen_xref = TRUE;            /* generate X Reference list */
  77. boolean gen_qxref = TRUE;            /* generate quotes in X Reference list */
  78. boolean gen_dir = TRUE;                /* generate Function directory */
  79. boolean fst_tbl = TRUE;
  80. boolean comment, quote, squote, instrng, found_it, define;
  81.  
  82. int lcol;
  83. unsigned char buf[600], lineimage[520], title[60], heading[26];
  84. unsigned char fmt[] =
  85.         {"\fListing of file: %s   Catalogued on %s   Page: %d\n\n\0"};
  86. unsigned char xhead[] =
  87.         {"\fX-Ref of file: %s     Catalogued on %s   Page: %d\n\n\0"};
  88. unsigned char dhead[] =
  89.         {"\fFunction Dir. for: %s   Catalogued on %s Page: %d\n\n\0"};
  90. unsigned char *msg[3] =
  91.         {"overflowed quote storage area at line %d\n",
  92.          "Exceeded NFCN functions with %s\n",
  93.          "No memory available to store reference %s in %s\n"};
  94.          
  95. extern FILE *fclose();
  96. FILE *prn, *fd;
  97. unsigned char output[60]={"PRN"};
  98.  
  99. char *def_keys[DKW] = {"char", "double", "enum", "float", "int", "long",
  100.                        "signed", "short", "struct", "typedef", "unsigned",
  101.                        "void"};
  102. char *keyword[KW] = {"auto", "break", "case", "const", "continue", "default",
  103.                       "do", "else", "entry", "extern", "for", "goto",
  104.                      "if", "register", "return", "sizeof","static",
  105.                      "switch", "union", "volatile", "while" };
  106.                  
  107. int s = 0;
  108. char symbol[256] = "\0";
  109. char global[7] = "Global";            
  110. char func_name[33];
  111.  
  112. struct refno {
  113.         struct refno *nxt;            /* pointer to next NREF entries */
  114.         int ref_num[NREF + 1];        /* line number symbol found on */
  115.        };
  116.        
  117. struct ref {
  118.             char *name;                    /* pointer to symbol name */
  119.             struct ref *nxt;
  120.             struct refno *fst_no;
  121.            };
  122.  
  123. int dcnt = 0;                    /* count of entries in Directory Table */           
  124. struct fdir {
  125.         char *source;            /* pointer to function name of line number */
  126.         int org_no;                /* first statement of function */
  127.         } dirtbl[NFCN];
  128.         
  129.                   
  130. typedef struct ref reference, *refptr;
  131. typedef struct refno ref_line, *noptr;
  132.  
  133.     
  134. refptr xref_top, xref_null, add_sym(), find_sym();
  135.     
  136. /* top of page routine */
  137.  
  138. void toppage(pr)
  139. FILE *pr;
  140.  
  141. {
  142.     if (listing) fprintf(pr,fmt,title,heading,pagect);
  143.     linect=1;
  144.     pagect++;
  145. }
  146.  
  147. /* tabbing Modul Calculation */
  148.  
  149. int mod(no,k)
  150. int no,k;
  151.  
  152. {
  153.     int l;
  154.     
  155.     l = no / k;
  156.     l = l * k;
  157.     return (no - l);
  158. }
  159.  
  160. /* main program */
  161.  
  162. main(argc,argv)
  163. int argc;
  164. unsigned char *argv[];
  165.  
  166. {
  167.     
  168.     void process_sym(unsigned char), collect_sym(unsigned char);
  169.     void dir_prt(void), xref_prt(void);
  170.     int i, j, l, ltab, q, kk, jj, n;
  171.     unsigned char k, lt[2], file_name[254];
  172.     int *pb, lbrace, rbrace, dbrace, lparen, rparen, lbrack, rbrack;
  173.     boolean cont_line, bold; 
  174.     
  175.     /* set up heading containg date and time of listing */
  176.     
  177.     xref_null = (refptr) NULL;
  178.     xref_top =     xref_null;            /* initialize xref_top for Add_Sym rtn */
  179.         
  180.     time(&timer);                    /* set up date in header */
  181.     memcpy(&time_stamp,localtime(&timer),18);
  182.     strcpy(heading,asctime(&time_stamp));
  183.     i = 11;
  184.     for (j = 20; j < 24; i++, j++) heading[i] = heading[j];
  185.     heading[i] = '\0';
  186.     fprintf(stderr,"C Program Listing Version 1.3\n");
  187.     
  188.     lt[1] = '\0';
  189.     
  190.     file_name[0] = '\0';
  191.     for(i = 1; i < argc; i++)
  192.         {
  193.         strcpy(buf, strupr(argv[i]));
  194.         if (buf[0] == '/')
  195.             {
  196.             kk = buf[1];
  197.             switch (kk)
  198.                 {
  199.                 case 'L':
  200.                     listing = FALSE;
  201.                     printf("No listing will be generated\n");
  202.                     break;
  203.                 case 'Q':
  204.                     gen_qxref = FALSE;
  205.                     printf("No quotes in X-Reference will be generated\n");
  206.                     break;
  207.                 case 'X':
  208.                     gen_xref = gen_qxref = FALSE;
  209.                     printf("No X-Reference will be generated\n");
  210.                     break;
  211.                 case 'D':
  212.                     gen_dir = FALSE;
  213.                     printf("No directory of functions will be generated\n");
  214.                     break;
  215.                 case 'P':
  216.                     for (j = 2, q = 0 ; buf[j] != '\0'; j++, q++) output[q] = buf[j];
  217.                     output[++q] = '\0';
  218.                     printf("Print file: %s requested\n", output);
  219.                     break;
  220.                 default:
  221.                     printf("Unknow option: %s\n", argv[i]);
  222.                 }
  223.             }
  224.             else
  225.             {
  226.             if (file_name[0] == '\0')
  227.                 strcpy(file_name, buf);
  228.                 else
  229.                 {
  230.                 printf("More than one input file name: %s and %s\n", file_name, buf);
  231.                 exit(1);
  232.                 }
  233.             }
  234.         }
  235.                     
  236.     if (file_name[0] == '\0')        /*get user file name from terminal*/
  237.         {
  238.         printf("Key-In input filename: ");
  239.         gets(file_name);
  240.         printf("\n");
  241.         }
  242.         else
  243.         printf("Listing Of File: %s \n",file_name);
  244.         
  245.                                     /*convert file name to filename.c*/
  246.  
  247.     if (index(buf, '.') == NULL) strcat(file_name,".c");
  248.                                 
  249.     prn = fopen(output,"w");        /*open printer*/
  250.     if(prn == NULL)
  251.         {
  252.         fprintf(stderr,"Assignment of print device: %s failed.",output);
  253.         exit(1);
  254.         }
  255.     fd=fopen(file_name,"r");        /*open file to list*/
  256.     if (fd==NULL)
  257.         {
  258.         fprintf(stderr,"Cannot Open Input File: %s \n",file_name);
  259.         exit(1);
  260.         }
  261.     strcpy(title,file_name);
  262.     
  263.     linect = pagect = 1;            /*set page & line count to one*/
  264.     toppage(prn);                    /*take top of page action*/
  265.     
  266.                                     /*initialize balanced counters*/
  267.                                 
  268.     stmnt = j = lcol = rbrack = lbrack = 0;
  269.     rbrace = lbrace = dbrace = rparen = lparen = 0;
  270.     comment=squote=instrng=quote=cont_line=define=FALSE;
  271.     
  272.                                 /* START ANALYSIS OF SOURCE */
  273.                     
  274.     while(fgets(lineimage,519,fd) != NULL)
  275.         {
  276.         jj = strlen(lineimage);
  277.         for(i=0; k=lineimage[i], (k!='\0' && i<jj); i++)
  278.             {
  279.             kk = k;
  280.             if (kk == '\n')
  281.                 {
  282.                 process_sym(k);
  283.                 lines++;
  284.                 }
  285.             if (comment == FALSE && instrng == FALSE)
  286.                   {
  287.     /*
  288.     switch is entered when processing outside a comment
  289.     or string.  If in a comment or string (either " or ') then
  290.     the if statement drops thru to the else at the
  291.     conclusion of the loop to turn processing back on
  292.     In the case of alphanumerics the loop is totally ignored.
  293.     */
  294.             
  295.                 if (isspace(k))
  296.                     process_sym(k);
  297.                     else
  298.                     {
  299.                     if (isalnum(k))
  300.                         collect_sym(k);
  301.                         else
  302.                         {             
  303.                         switch (kk)
  304.                             {
  305.                             case '{':
  306.                                 if((level == 0) && !pre_def) define = FALSE;
  307.                                 level++;
  308.                                 process_sym(k);
  309.                                 lbrace++;
  310.                                 if (define) dbrace++;
  311.                                 break;
  312.                             case '}':
  313.                                 rbrace++;
  314.                                 level--;
  315.                                 process_sym(k);
  316.                                 if (define) dbrace--;
  317.                                 break;
  318.                             case '(':
  319.                                 lparen++;
  320.                                 process_sym(k);
  321.                                 break;
  322.                             case ')':
  323.                                 rparen++;
  324.                                 process_sym(k);
  325.                                 break;
  326.                             case '[':
  327.                                 lbrack++;
  328.                                 process_sym(k);
  329.                                 break;
  330.                             case ']':
  331.                                 rbrack++;
  332.                                 process_sym(k);
  333.                                 break;
  334.                             case '/':
  335.                                 process_sym(k);
  336.                                 comment = (lineimage[i+1] == '*');
  337.                                 break;
  338.                             case ';':
  339.                                 if ((dbrace == 0) || !pre_def) define = FALSE;
  340.                                 process_sym(k);
  341.                                 stmnt++;
  342.                                 break;
  343.                             case '\'':
  344.                                 quote =! squote;
  345.                                 if (gen_qxref && quote)
  346.                                     {
  347.                                     symbol[0] = k;
  348.                                     s = 1;
  349.                                     }
  350.                                 instrng = quote|squote;
  351.                                 break;
  352.                             case '"':
  353.                                 process_sym(k);
  354.                                 squote = !quote;
  355.                                 if (gen_qxref && squote)
  356.                                     {
  357.                                     symbol[0] = k;
  358.                                     s = 1;
  359.                                     }
  360.                                 instrng = squote|quote;
  361.                                 break;
  362.                             case ',':
  363.                                 process_sym(k);
  364.                                 break;
  365.                             case '+':
  366.                                 process_sym(k);
  367.                                 break;
  368.                             case '=':
  369.                                 process_sym(k);
  370.                                 break;
  371.                             case '-':
  372.                                 process_sym(k);
  373.                                 break;
  374.                             case '*':
  375.                                 process_sym(k);
  376.                                 break;
  377.                             case '.':
  378.                                 if (pre_def)
  379.                                     collect_sym(k);
  380.                                     else
  381.                                     process_sym(k);
  382.                                 break;
  383.                             case '<':
  384.                                 process_sym(k);
  385.                                 break;
  386.                             case '>':
  387.                                 process_sym(k);
  388.                                 break;
  389.                             case '&':
  390.                                 process_sym(k);
  391.                                 break;
  392.                             case '|':
  393.                                 process_sym(k);
  394.                                 break;
  395.                             case ':':
  396.                                 process_sym(k);
  397.                                 break;
  398.                             case '!':
  399.                                 process_sym(k);
  400.                                 break;
  401.                             default:
  402.                                 collect_sym(k);
  403.                             }
  404.                         }
  405.                     }
  406.             }
  407.             else                /*if comment or instrng == TRUE*/
  408.             { 
  409.                 if (comment && k=='*' && lineimage[i+1]=='/') comment = FALSE;
  410.                 if (quote)
  411.                     if ((k == '\'') && (lineimage[i-1] != '\\'
  412.                      || (lineimage[i-2]=='\\' && lineimage[i-1]=='\\')))
  413.                         {
  414.                         quote = FALSE;
  415.                         if (gen_qxref)
  416.                             {
  417.                             symbol[s++] = k;
  418.                             process_sym(k);
  419.                             }
  420.                         }
  421.                         else
  422.                         {
  423.                         if ((s > 253) && !overflow)
  424.                             {
  425.                             printf(msg[0], lines);
  426.                             overflow = TRUE;
  427.                             }
  428.                             else
  429.                             if (gen_qxref) symbol[s++] = k;
  430.                         }
  431.  
  432.                 if (squote)
  433.                     {
  434.                     if (k == '"')
  435.                         {
  436.                         squote=FALSE;
  437.                         if (gen_qxref)
  438.                             {
  439.                             symbol[s++] = k;
  440.                             process_sym(k);
  441.                             }
  442.                         }
  443.                         else
  444.                         {
  445.                         if ((s > 253) && !overflow)
  446.                             {
  447.                             printf(msg[0], lines);
  448.                             overflow = TRUE;
  449.                             }
  450.                             else
  451.                             if (gen_qxref) symbol[s++] = k;
  452.                         }
  453.                     }
  454.                 instrng = quote | squote;
  455.             }
  456.             if (k=='\t')
  457.                 {
  458.                 ltab = j + (TAB-mod(j,TAB));
  459.                 while (j < ltab)
  460.                     {
  461.                     j++;
  462.                     buf[lcol++] = ' ';
  463.                     }
  464.                 }
  465.                 else
  466.                 {
  467.                 j++;
  468.                 buf[lcol++] = k;
  469.                 }
  470.             if (j > CHPL || k == '\n')    /* Check for end of line */
  471.                 {
  472.                 if (k != '\n') buf[lcol++]='\n';
  473.                 buf[lcol]='\0';
  474.                 if (listing)
  475.                     {
  476.                     if (cont_line)
  477.                         fprintf(prn,"         : %s", buf);
  478.                         else
  479.                         {
  480.                         lt[0] = ' ';
  481.                         if (comment) lt[0] = '*';
  482.                         if (quote) lt[0] = '\'';
  483.                         if (squote) lt[0] = '"';
  484.                         if (k == '\n') 
  485.                             fprintf(prn,"%s%2d%6d: %s",lt, level, lines, buf);
  486.                             else
  487.                             fprintf(prn,"%s%2d%6d: %s",lt, level, lines + 1, buf);
  488.                         }
  489.                     }
  490.                 if (k == '\n')
  491.                      cont_line = FALSE;
  492.                      else
  493.                      cont_line = TRUE;
  494.                 j = lcol = 0;
  495.                 if (linect++>LPP) toppage(prn);
  496.                 }
  497.         }
  498.     }
  499.     if(lcol > 0)        /* Sometimes the last line doesn't have a CR */
  500.         {
  501.         process_sym('\n');
  502.         lt[0] = ' ';
  503.         if (comment) lt[0] = '*';
  504.         if (quote) lt[0] = '\'';
  505.         if (squote) lt[0] = '"';
  506.         buf[lcol++]='\n';
  507.         buf[lcol]='\0';
  508.         fprintf(prn,"%s%2d%6d: %s",lt, level, ++lines, buf);
  509.         }
  510.     fclose(fd);
  511.     if (level==0 && rbrack==lbrack && rparen==lparen)
  512.         fprintf(prn,"\n%d Statements in source code. Braces, brackets and parenthesis are balanced.\n",stmnt);
  513.         else
  514.         {
  515.         fprintf(prn,"\nUnbalanced pairs { %d, } %d, [ %d, ] %d, ( %d, ) %d\n",
  516.         lbrace,rbrace,lbrack,rbrack,lparen,rparen);
  517.         }
  518.     listing = TRUE;
  519.     if (gen_dir && (dcnt > 0)) dir_prt();
  520.     if (gen_xref) xref_prt();
  521.     fclose(prn);
  522.     
  523. }/* end main */
  524.  
  525. void collect_sym(c)
  526.     unsigned char c;        /* This routine collects each symbol which
  527.                                will be added to the X-Ref list.
  528.                                It will check for symbols exceeding
  529.                                32 characters                            */    
  530. {
  531.     if (! overflow)
  532.         {
  533.         if (s > 31)
  534.             {
  535.             symbol[32] = '\0';
  536.             printf("Symbol %s greater than 32 characters at line %d\n", symbol, lines);
  537.             overflow = TRUE;
  538.             }
  539.             else
  540.             symbol[s++] = c;
  541.         }
  542.         
  543. } /* end collect_sym */
  544.  
  545. void process_sym(token)
  546.     unsigned char token;        /* Upon each break character this routine
  547.                                    will check for a proceeding symbol.  If
  548.                                    there is it will determine if the symbol
  549.                                    belongs in the X-Ref table.  It will 
  550.                                    check for it already in the X-Ref and 
  551.                                    simply add the line reference or it will
  552.                                    add the symbol name in sort order        */
  553.  
  554. {
  555.     void bold_symbol(void);
  556.     boolean all_numeric();
  557.     refptr scurr, swrk, sprev, sref;
  558.     noptr lcurr, lwrk, lprev;
  559.     int i;
  560.  
  561.     if (s == 0) return;            /* check for null */
  562.     symbol[s] = '\0';            /* end the colection of symbol characters */
  563.     s = 0;                        /* reset collection pointer for next symbol*/
  564.     overflow = FALSE;            /* reset any symbol collection overflow */
  565.     
  566.     if (symbol[0] == '#')         /* ignore compiler commands */
  567.         {
  568.         if (listing) bold_symbol();
  569.         return;
  570.         }
  571.     if (all_numeric(symbol)) return;    /* ignore all numbers */
  572.     
  573.     for (i = 0; (i < DKW); i++)            /* drop C keywords */
  574.         if (strcmp(symbol, def_keys[i]) == 0)
  575.             {
  576.             define = TRUE;                /* this is a data definition */
  577.             if (listing) bold_symbol();
  578.             return;
  579.             }
  580.     
  581.     for (i = 0; (i < KW); i++)            /* drop C keywords */
  582.         if (strcmp(symbol, keyword[i]) == 0) 
  583.             {
  584.             if (listing) bold_symbol();
  585.             return;
  586.             }
  587.         
  588.     if ((level == 0) && (token == '('))    /* check for function definition */
  589.         {
  590.         p_func = TRUE;
  591.          strcpy(func_name, symbol);
  592.          fline = lines + 1;
  593.          }
  594.         
  595.     if (gen_xref)
  596.         {    
  597.         swrk = find_sym(symbol);
  598.         if (! found_it) swrk = add_sym(symbol);
  599.         lcurr = swrk->fst_no;
  600.         while (lcurr->nxt != (noptr) NULL) lcurr = lcurr->nxt;
  601.         for (i = 0; ((lcurr->ref_num[i] != 0)&&(i <= NREF)); i++);
  602.         if (i > NREF)
  603.             {    
  604.             lwrk = (noptr) malloc(sizeof(ref_line));    /* New Entry */
  605.             if (lwrk == (noptr) NULL)
  606.                 {
  607.                 printf("No memory available to line references for %s in %s\n", symbol, func_name);
  608.                 exit(1);
  609.                 }
  610.             lcurr->nxt = lwrk;                            /* link it in */
  611.             lwrk->nxt = (noptr) NULL;
  612.             lwrk->ref_num[0] = lines + 1;
  613.             for (i = 1; i <= NREF; i++) lwrk->ref_num[i] = 0;
  614.             }
  615.             else
  616.             lcurr->ref_num[i] = lines + 1;        /* store in old entry spare */
  617.         }
  618.         
  619.     if (!define && p_func && (level > 0))                /* store confirmed function names */
  620.         {
  621.         printf("Processing Function: %s\n", func_name);
  622.         pre_def = FALSE;
  623.         p_func = FALSE;
  624.         if (gen_dir && gen_xref)
  625.             {
  626.             swrk = find_sym(func_name);
  627.             if (! found_it)
  628.                 printf("Function name: %s not found in ref. table\n", func_name);
  629.                 else
  630.                 {    
  631.                  dirtbl[dcnt].source = swrk->name;
  632.                  dirtbl[dcnt++].org_no = fline;
  633.                  if (dcnt >= NFCN)
  634.                      {
  635.                      printf(msg[1], func_name);
  636.                      exit(1);
  637.                      }
  638.                  }
  639.              }
  640.              else
  641.              {
  642.              if (gen_dir)
  643.                  {
  644.                  dirtbl[dcnt].source = strdup(func_name);
  645.                  dirtbl[dcnt++].org_no = fline;
  646.                  if (dcnt >= NFCN)
  647.                      {
  648.                      printf(msg[1], func_name);
  649.                      exit(1);
  650.                      }
  651.                  }
  652.              }
  653.  
  654.          }
  655.     return;
  656.          
  657. } /* end of process_sym */
  658.  
  659. void bold_symbol()            /* This routine will add Esc E and Esc F
  660.                                around symbols which are requested to
  661.                                be made BOLD in the printer listing    */
  662.  
  663. {
  664.     int l, i;
  665.     
  666.     l = lcol - strlen(symbol);
  667.     buf[l++] = '\x1b';
  668.     buf[l++] = 'E';
  669.     for(i = 0; symbol[i] != '\0'; i++, l++) buf[l] = symbol[i];
  670.     buf[l++] = '\x1b';
  671.     buf[l++] = 'F';
  672.     lcol = l;
  673.     return;
  674.         
  675. } /* end of bold_symbol */
  676.  
  677. boolean all_numeric(f)
  678.     char f[];
  679.     
  680. {
  681.  
  682.     int i;
  683.     
  684.     i = 0;
  685.     if (f[i] == '\0') return(FALSE);
  686.     while ( f[i] != '\0')
  687.         {
  688.         if (f[i] != '.')
  689.             {
  690.             if (f[i] < '0') return(FALSE);
  691.             if (f[i++] > '9') return(FALSE);
  692.             }
  693.             else
  694.             i++;
  695.         }
  696.     return (TRUE);
  697.          
  698. } /* end of all_numeric */
  699.  
  700. refptr add_sym(sym)
  701.     char sym[33];            /* This routine will add a symbol to the X-Ref 
  702.                                list in sort order.  It gets the memory
  703.                                space from MALLOC to add the X-Ref entries */
  704.     
  705. {
  706.     char *smem, *fptr;
  707.     int i;
  708.     refptr curr, wrk, prev;
  709.     noptr lwrk;
  710.     
  711.     curr = (refptr) malloc(sizeof(reference));
  712.     if (curr == xref_null)
  713.         {
  714.         printf(msg[2], sym, func_name);
  715.         exit(1);
  716.         }
  717.     smem = malloc(strlen(sym) + 1);
  718.     if (smem == (char*) NULL)
  719.         {
  720.         printf(msg[2], sym, func_name);
  721.         exit(1);
  722.         }
  723.     curr->name = smem;
  724.     strcpy(curr->name, sym);
  725.     if (xref_top == xref_null)        /* link new entry into sort order */
  726.         {
  727.         curr->nxt = xref_null;        /* end list for this table */
  728.         xref_top = curr;            /* first time so set top of list */
  729.         }
  730.         else
  731.         {
  732.         wrk = find_sym(sym);
  733.         if (wrk == xref_null)
  734.             {
  735.             curr->nxt = xref_top;    /* top is this one's next */
  736.             xref_top = curr;        /* insert into top of list */
  737.             }
  738.             else
  739.             {
  740.             curr->nxt = wrk->nxt;    /* insert after item => */
  741.             wrk->nxt = curr;
  742.             }
  743.         }
  744.     lwrk = (noptr) malloc(sizeof(ref_line));
  745.     if (lwrk == (noptr) NULL)
  746.         {
  747.         printf("No memory available to line references for %s in %s\n", sym, func_name);
  748.         exit(1);
  749.         }
  750.     curr->fst_no = lwrk;            /* set first linkt to reference number */
  751.     lwrk->nxt = (noptr) NULL;
  752.     for (i = 0; i <= NREF; i++) lwrk->ref_num[i] = 0;
  753.     return(curr);
  754.     
  755. } /* end of add_sym */
  756.              
  757. refptr find_sym(sym)        /* Find a symbol reference in table */
  758.     char sym[33];            /* 
  759.                                This routine will return a pointer that 
  760.                                will indicate where the item is or should
  761.                                be linked in to the list. A boolean indicator
  762.                                will specify whether the routine found the
  763.                                symbol or not.
  764.                                
  765.                                Returned pointer is reference point of symbol
  766.                                if the boolean found_it is TRUE.
  767.                                
  768.                                If the boolean found-it is FALSE the returned 
  769.                                pointer can have two meanings:
  770.                                
  771.                                        NULL  - Indicates link in from the
  772.                                                top pointer
  773.                                        !NULL - Indicates the new item should
  774.                                                be linked after the item pointed
  775.                                                to
  776.                             */
  777.     
  778. {
  779.  
  780.     refptr wrk, prev;
  781.                             
  782.     prev = xref_null;
  783.     wrk = xref_top;
  784.     while ((wrk != xref_null)&&(strcmp(wrk->name, sym) < 0))
  785.         {
  786.         
  787. /*    Debug stepping through reference list
  788.         printf("stepping: o=%x n=%x oldname=%s\n", wrk, wrk->nxt, wrk->name); */
  789.         
  790.         prev = wrk;
  791.         wrk = wrk->nxt;
  792.         }
  793.     found_it = FALSE;
  794.     if (wrk != xref_null)
  795.         {
  796.         found_it = (strcmp(wrk->name, sym) == 0);
  797.         if (found_it) prev = wrk;
  798.         }
  799.         
  800. /*    DEBUG DUMP OF XREF TABLE         
  801.     if (found_it)
  802.         printf(" - found symbol position at %x\n", prev);
  803.         else
  804.         printf(" - not found - link from %x\n", prev);*/
  805.     
  806.     return(prev);
  807.     
  808. } /* end of find_sym */
  809.  
  810. void dir_prt()                /* This routine will print out the list of
  811.                                detected functions.  The format is set
  812.                                up to be a three column per page listing */
  813.  
  814. {
  815.  
  816.      char col1[27], col2[27], col3[27];
  817.      int i, j, k, c1, c2, oc2, c3, oc3, cend;
  818.      
  819.      pagect = 1;
  820.     strcpy(fmt, dhead);
  821.     toppage(prn);
  822.     j = min(dcnt/3, 50);
  823.     dcnt = dcnt - 1;
  824.     c1 = cend = 0;
  825.     if (dcnt < 50)
  826.         oc2 = c3 = c2 = oc3 = dcnt +1;
  827.         else
  828.         if (dcnt < 100)
  829.             {
  830.             c2 = oc2 = 50;
  831.             c3 = oc3 = dcnt + 1;
  832.             }
  833.             else
  834.             {
  835.             c2 = oc2 =j;
  836.             c3 = oc3 = c2 + j;
  837.             }
  838.     while (cend <= dcnt)
  839.         {
  840.         col1[0]=col2[0]=col3[0]='\0';
  841.         if (c1 < oc2)
  842.             {
  843.             sprintf(col1, "%6d %-20s", dirtbl[c1].org_no, dirtbl[c1].source);
  844.             cend = max(cend, ++c1);
  845.             }
  846.         if (c2 < oc3)
  847.             {
  848.             cend = max(cend, c2);
  849.             sprintf(col2, "%6d %-20s", dirtbl[c2].org_no, dirtbl[c2].source);
  850.             c2++;
  851.             }
  852.         if (c3 <= dcnt)
  853.             {
  854.             cend = max(cend, c3);
  855.             sprintf(col3, "%6d %-20s", dirtbl[c3].org_no, dirtbl[c3].source);
  856.             c3++;
  857.             }
  858.         fprintf(prn,"%-27s%-27s%-27s\n",col1, col2, col3);
  859.         linect++;
  860.         if (linect > 50)
  861.             {
  862.             toppage(prn);
  863.             c1 = cend + 1;
  864.             c2 = oc2 = c1 + 50;
  865.             c3 = oc3 = c2 + 50;
  866.             }
  867.         }
  868. }
  869.  
  870. void xref_prt()                /* This routine will print out a cross-reference
  871.                                listing of all symbols stored in the X-Ref
  872.                                table.  Symbols are given at least 12
  873.                                characters before the line number are printed. */
  874.  
  875. {
  876.      char psym[65];
  877.      int i, p, t;
  878.      refptr curr, next;
  879.      noptr lc;
  880.          
  881.     pagect = 1;                                /* initialize page number */
  882.     strcpy(fmt, xhead);                        /* set up new header */
  883.     linect = 55;                            /* force top of page */
  884.     next = xref_top;                        /* get first X-Ref entry */
  885.     while (next != xref_null)
  886.         {
  887.         if (linect > 50) toppage(prn);
  888.         curr = next;                        /* get next Xref Entry */
  889.         next = curr->nxt;            
  890.         lc = curr->fst_no;                    /* get first line number table */        
  891.         i = 0;
  892.         fprintf(prn,"%s", curr->name);
  893.         p = strlen(curr->name);
  894.         if (p < 12)                            /* start line numbers a column 12 */
  895.             while (p <= 11)
  896.                 {
  897.                 fprintf(prn, " ");
  898.                 p++;
  899.                 }
  900.             else
  901.             {                                /* or on the even 6th character past column 12 */
  902.             t = mod(p, 6);
  903.             if (t != 6)
  904.                 for (t = 6 - t; t > 0; t-- , p++) fprintf(prn, " ");
  905.             }
  906.         while ((lc != (noptr) NULL) && (lc->ref_num[i] > 0))
  907.             {
  908.             fprintf(prn, "%6d", lc->ref_num[i]); /* print a line number */
  909.             i = i + 1;
  910.             if (i > NREF)
  911.                 {                        /* Exhausted this table set */
  912.                 lc = lc->nxt;            /* Get next set of NREF entries */
  913.                 i = 0;
  914.                 }
  915.             p = p + 6;                    /* Bump printed columns */
  916.             if (p >= 74)
  917.                 {
  918.                 xref_pager();
  919.                 fprintf(prn, "            ");    /* put in leading spaces */
  920.                 p = 12;
  921.                 }
  922.             }
  923.         if (p > 0) xref_pager();
  924.         }
  925.                         
  926.  
  927. }
  928.  
  929. xref_pager()
  930.  
  931. {
  932.     linect++;                            /* End of print line */
  933.     if (linect > 57)
  934.         toppage(prn);                    /* Bump the page */
  935.         else
  936.         fprintf(prn, "\n");                /* Just print a CR */
  937. }